/*
 * Amadeus Confidential Information:
 * Unauthorized use and disclosure strictly forbidden.
 * @1998-2011 - Amadeus s.a.s - All Rights Reserved.
 */
package com.amadeus.spin.devtool.soap.shooter.filter;

import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.w3c.dom.Node;

import com.amadeus.spin.devtool.soap.shooter.FatalException;
import com.amadeus.spin.devtool.soap.shooter.config.ConfigurationParameters;
import com.amadeus.spin.devtool.soap.shooter.config.SoapShooterInitializationException;
import com.amadeus.spin.devtool.soap.shooter.config.SoapshooterScenario;
import com.amadeus.spin.standard.util.FileUtils;
import com.amadeus.spin.standard.util.XPathHelper;

/**
 * Adds default filters that can be used inside the scenarios
 *
 */
public abstract class DefaultFilterInitializer {

  private static final String VERSION_DECIMAL = ".";

  /**
   * The filter names that will be used in the scenarios
   */
  public static final String APPLICATION_SERVER_FILTER = "SOAP_APPLICATION_SERVER";

  public static final String SOAP_SCHEMA_VERSION_FILTER = "SOAP_SCHEMA_VERSION";

  /**
   * The list of attributes that will be checked to find the version.
   */
  private static final Pattern[] ATTRIBUTES = new Pattern[] {
      Pattern.compile(".*noNamespaceSchemaLocation=\"(.*)\".*".toLowerCase(Locale.US)),
      Pattern.compile(".*Version=\"(.*)\".*".toLowerCase(Locale.US)) };

  /**
   * The pattern that defines where the URL that encloses the Version
   */
  private static final Pattern PATTERN_VERSION = Pattern.compile("(?:.*V)(\\d+(\\.)?\\d+(\\.)?\\d+)",
      Pattern.CASE_INSENSITIVE);

  private static Logger logger = Logger.getLogger(DefaultFilterInitializer.class);

  /**
   * Sets the default filters that can be used within the scenarios
   *
   * @throws FatalException
   * @throws SoapShooterInitializationException
   */
  public static void setDefaultFilters(SoapshooterScenario scenario) throws FatalException,
      SoapShooterInitializationException {
    if (ConfigurationParameters.getFilterHandler() != null) {

      // The base URL of the target server is stored as a filter.
      ConfigurationParameters.getFilterHandler().addFilter(APPLICATION_SERVER_FILTER, "string",
          ConfigurationParameters.getServer());

      // The version number if it exists.
      String version = null;
      if (ConfigurationParameters.isUseCustomSchemaVersion()) {
        version = ConfigurationParameters.getCustomSchemaVersion();
      }
      else {
        // Only the first node of the scenario is checked
        Node request = scenario.getNode("/scenario/request");
        String currentFile = ConfigurationParameters.getInputDir() + "/" + XPathHelper.getProperty(request, "@input");

        String xmlIn = FileUtils.getXmlContent(currentFile, logger);
        version = getSchemaVersion(xmlIn);
        if (version != null) {
          logger.info(SOAP_SCHEMA_VERSION_FILTER + " filter set to " + version
              + ", it was read from file : " + getFileNameFromPath(currentFile));
        }
      }
      if (version != null) {
        ConfigurationParameters.getFilterHandler().addFilter(SOAP_SCHEMA_VERSION_FILTER, "string", version);
      }
    }
  }

  private static String getFileNameFromPath(String mixedPath) {
    int lastSlashSeparator = mixedPath.lastIndexOf('/');
    int lastAntiSlashSeparator = mixedPath.lastIndexOf('\\');
    int lastFileSeparator = Math
        .max(lastAntiSlashSeparator, lastSlashSeparator);
    return mixedPath.substring(lastFileSeparator + 1);
  }

  /**
   * Extracts the version value from an xml scenario
   * Searches for the version defined in the ATTRIBUTES variable
   *
   * @param xml
   * @return the version or null if not found
   */
  protected static String getSchemaVersion(String xml) {
    // Everything is processed using lower case to avoid confusions
    xml = xml.toLowerCase();
    String version = null;
    for (Pattern attribute : ATTRIBUTES) {
      Matcher matcher = attribute.matcher(xml);
      if (matcher.matches()) {
        String valueToAnalyze = matcher.group(0);
        try {
          version = getVersionFromString(valueToAnalyze);
          if (version != null) {
            // Version found, end of the loop
            break;
          }
        }
        catch (Exception e) {
          // If an exception occurs, we try to find the version within the next attribute
          continue;
        }
      }
    }
    return version;
  }

  /**
   * Uses a specific regexp pattern to extract a version from a string
   * If the version does not contain any ".", then it will be added
   *
   * @param valueToAnalyze
   * @return
   */
  private static String getVersionFromString(String valueToAnalyze) {
    String cleanValueToAnalyze = valueToAnalyze.replaceAll("\\\\+", "/");
    Matcher matcherVersion = PATTERN_VERSION.matcher(cleanValueToAnalyze);
    matcherVersion.find();
    String version = matcherVersion.group(1);
    // For cases with no "." in the version
    if (!version.contains(VERSION_DECIMAL)) {
      version = version.substring(0, 2) + VERSION_DECIMAL + version.substring(2);
    }
    return version;
  }
}
